Tim_ATmega328p.c

					
#include "Tim_ATmega328p.h"

/* Setting period of simple continuous interrupts for a chosen Timer
 *  Timer (TIM0, TIM1, TIM2)
 *  Mode - Mode of how the Timer works (PWM, OVERFLOW_INT, ADC_TRIGGERING)
 *  Period_us - Period for PWM or interrupt generation
 */
my_bool TIMER_Set(tim_t Timer, tim_mode_t Mode, unsigned long Period_us)
{
  switch(Timer) 
  {
    case TIM0: // For AVR MCUs - 8 Bit Timer
    {
      switch(Mode)
      {
        case PWM:
        {
          
        }break;
        case OUT_COMP_A:
        {
          
        }break;
        default: ;//Serial.println("The mode of TIM2 is still not handled in this version");
      } // switch(Mode)
    } break; // case TIM0

    case TIM1:  // For AVR MCUs - 16 Bit Timer
    {
      switch(Mode)
      {
        case OUT_COMP_A:
        {
          
        } break; // case OVERFLOW_INT
		case PWM: // PWM for the channel A (experimental) Fast PWM, 10-bit, TOP = 0x03FF, PWM Pin - PB1 (Arduino D9)
		{
			// Here - Period_us = PWM Duty Cycle
			// F_PWM = F_CPU / (psc * (1 + 0x03FF)) 
			TCCR1A |= (1<<COM1A1) | (1<<WGM11) | (1<<WGM10);
			TCCR1B |= (1<<WGM12);
			TIMSK1 |= (1<<TOIE1);             // Enable Timer 1 overflow interrupt 
			
			// Prescaler = 0, PWM Period = 15625 Hz
			if(Period_us > 100)
			{
				Period_us = 100;
			}
			OCR1A = (0x03FF * Period_us / 100);
			
			TCCR1B |= (1<<CS10); // Start timer
		} break; 
        default: ;//Serial.println("The mode of TIM2 is still not handled in this version");
      } // switch(Mode), TIM 1
    } break; // case TIM1
      
    case TIM2:  // For AVR MCUs - 8 Bit Timer
    {
      switch(Mode)
      {
		case TIM2_A_SOUND_PWM:  // the following setting is made for the "Intercom" project. Setting is made for the same frequency as ADC Triggering. the commented section - for a free project.
        {
		 
         /**************** Chosen PWM Mode is "Fast PWM" using Channel A with top on 0xFF (bits WGM22..WGM20 = 3 = 0b011) ****************/
         /*                                    /\  /\ 
          *                                   /  \/  \/
          *                                   _|¯|_|¯|_
          */
          TCCR2A |= (1<<COM2A1) | (1<<WGM21) | (1<<WGM20);			// COM2A1-COM2A0 = 10: Non inverting
																					// WGM22-WGM20 = 011: Fast PWM 8-bit
															   
          // fOC1PWM = f_CPU / (N * (1 + TOP)); Where N is Prescaler and TOP is 0xff in the chosen mode
        
          TCNT2 = 0;								        
          OCR2A = 0;                        // No default PWM frequency
          TIMSK2 |= (1<<TOIE2);             // Enable Timer 2 overflow interrupt 
		  
		  TCCR2B |=  (1<<CS20) ;            // Start Timer 2 (prescaler = 1) 
        } break; // case TIM2_CHA_SOUND_PWM 
        case OUT_COMP_A:
        {
          uint16_t prescaler = set_TIM2_prescaler(Period_us, Mode);

          uint16_t Ticks_required;
          Ticks_required = F_CPU/prescaler/1e6*Period_us-1;
     
          OCR2A = (uint8_t)Ticks_required;
     
          TIMSK2=(1<<OCF2A);                             // Beginning of TIM2 COMP_A overflow interrupts
      
          //Serial.println("\nPrescaler of TIM2: " + (String)prescaler);
          //Serial.println("Ticks required: " + (String)Ticks_required);
          
        } break; // case OVERFLOW_INT:

        default: ;//Serial.println("The mode of TIM2 is still not handled in this version");
      } // switch(Mode)
    } break; // case TIM2;
  }   // switch(Timer)

  return HIGH;
}

/* Setting the PWM Value for the TIM1, set in a 10 bit Fast PWM Mode
*/
void TIM1_Set_PWM(uint8_t Duty_PWM)
{
	OCR1A = ((long)0x03FF * Duty_PWM / 100);
}

/*  Calculating the prescaler for the Timer
 *  Arguments:
 *    Period us - period value counted in us
 *    Mode - mode of Timer work
 */
uint16_t set_TIM2_prescaler(unsigned long Period_us, tim_mode_t Mode)
{
  /***************** Setting the CS20..CS22 prescaler Bits in TCCR2B Register ****************/
  /* 
   *  The prescaler setting is set to the highest precision but the highest amount of timer ticks
   *  to reduse the precision and decrease the amount of ticks - delete the "else's" after "if's"
   */

   uint16_t prescaler = 0;
   switch(Mode)
   {
      case OUT_COMP_A:
      {
          if(Period_us > 16320) // 16320 us is the highehst value for the 8Bit Timer 2
          {
              //Serial.println("TIM2 Period too high. Breakdown");
              return LOW;
          }
                  
          if((Period_us >= 1) && (Period_us < 15))  // Then needed Prescaler = 1 (no Prescaling)
          {
              TCCR2B |= (1<<CS20);
              prescaler = 1;
          } else
          if((Period_us >= 1) && (Period_us < 126)) // Then needed Prescaler = 8
          {
              TCCR2B |= (1<<CS21);
              prescaler = 8;
          } else
          if((Period_us >= 2) && (Period_us < 510)) // Then needed Prescaler = 32 // interruptions occur too slow with this Prescaler. reason unknown           
          {
              TCCR2B |= (1<<CS20) | (1<<CS21);
              prescaler = 32;
          } else
          if((Period_us >= 4) && (Period_us < 1020)) // Then needed Prescaler = 64
          {
              TCCR2B |= (1<<CS22);
              prescaler = 64;
          } else
          if((Period_us >= 8) && (Period_us < 2040)) // Then needed Prescaler = 128
          {
              TCCR2B |= (1<<CS20) | (1<<CS22);
              prescaler = 128;
          } else
          if((Period_us >= 16) && (Period_us < 4080)) // Then needed Prescaler = 256
          {
              TCCR2B |= (1<<CS21) | (1<<CS22);
              prescaler = 256;
          } else
          if((Period_us >= 64) && (Period_us <= 16320)) // Then needed Prescaler = 1024
          {
             TCCR2B |= (1<<CS20) | (1<<CS21) | (1<<CS22);
             prescaler = 1024;
          }
      } break; // case OVERFLOW_INT
      default:
      {
        //Serial.println("Chosen mode for TIM2 Prescaler setting is still not implemented.");
      }
   } // switch(Mode)
   
   return prescaler;
}